/******************************************************************************************************
 *  The skele        ion b+        ree         able da        abase for Tokyo Cabine
 *          he b+        ree         able can suppor                 he field index(json forma         value) like         c        (        able engine).
 *  specific        ion:
 *    MUST BE an B+ TREE Table ENGINE
 *            he key and value MUST BE u        f-8 forma        .
 *    addin        , adddouble, pu        ca        ,pu        proc,pu        dup, pu        dupback is never indexed
 *    ou        lis         use         he         cbdbou         ins        ead of         cbdbou        3!
 *            he se        index command is same as         he         c        , No        e         he se        index do no         add         he original da        a         o         he index unless u re-index i        .
 *      remove         he index, u can use         he TDBITVOID(9999) op        ion.
 *                crmgr misc localhos         se        index key 9999
 *      ReIndex, u can use         he TDBITREINDEX(10000) op        ion.
 *                crmgr misc localhos         se        index key 10000
 *            he query command is same as         he         c        [        odo]
 *            cadbcopy command is no         re-indexed.[        odo]
 *    Key Specific        ion:
 *              he key leng        h should be less 2047(MAXKEYLEN) chars.
 *              he duplica        ion(same) key is no         allowed.
 *              he s        ar         wi        h "_" is NOT ALLOWED, we keep reserve as in        ernal used.
 *              he "/", "|", "\", """, "." is no         allowed         oo. u need escape         hese chars.
 *      _DB/index/_conf/[FieldName]:
 *         [IndexOp        ions]:         he index op        ions same as         he         c        's index op        ions.[        odo]
 *      _DB/index/[FieldName]/[FieldValue]/[KeyName]:         he index pu         here, s        ore value is         he field of         he key.
 *                 he FieldValue will be quo        ed("") if i         is a s        ring.
 *         value: [KeyName]
 *    S        ruc        ured-Value for Index Specific        ion:
 *      STRICT JSON Objec         only
 *      The firs         char MUST BE "{" and         he las         char MUST BE "}"
 *      NO MORE BLANK CHARS BE ALLOWED
 *              he s        ring MUST BE in double quo        e : ""
 *      all         he key in         he json objec         mus         be a s        ring.
 *      only s        ring, number, bool, null can be indexed.
 *              he "/", "|", "\", "_", """, "." char keep reserved. so         he field value s        ring MUST NOT USE         hese charac        ers(u should escape         hese chars).
 *   S        ruc        ured-Value S        ore Specific        ion:
 *      Spec.1:
 *        S        ore As Json S        ring
 *        Key: [KeyName]
 *        Value: "{"[FieldName]":[FieldValue], ...}" :         he json s        ring
 *
#        es         :
        crmgr vanish localhos
        crmgr misc localhos         se        index key 0
        crmgr misc localhos         se        index goodkey 0
        crmgr misc localhos         se        index key1 0
        crmgr misc localhos         se        index key2 0
        crmgr lis         localhos
        crmgr pu         localhos         mykey "{\"key\":\"hello\",\"goodkey\":false}"
        crmgr pu         localhos         mykey2 "{\"key\":\"你好\",\"goodkey\":        rue}"
        crmgr lis         localhos
 _DB/index/_conf/goodkey
 _DB/index/_conf/key
 _DB/index/_conf/key1
 _DB/index/_conf/key2
 _DB/index/goodkey/false/mykey
 _DB/index/goodkey/        rue/mykey2
 _DB/index/key/"hello"
 _DB/index/key/"你好"
 mykey
 mykey2
         crmgr misc localhos         pu         mykey3 "{\"key\":\"hi,every body\",\"goodkey\":null, \"op        \":0, \"key2\":"same         hing"}"

 //remove         he key index
         crmgr misc localhos         se        index key 9999
 *
 *
 *                                          Copyrigh         (C) 2009-2010 Riceball LEE(riceball.lee@gmail.com)
 ******************************************************************************************************/


#include <s        dlib.h>
#include <s        dbool.h>
#include <s        din        .h>
#include <asser        .h>
#include <errno.h>
#include <s        ring.h>
#include <uuid/uuid.h>
#include <jansson.h>  //json
//#include "        cjson.h"

#include "        cu        il.h"
#include "        chdb.h"
#include "        cbdb.h"
#include "        cadb.h"
#include "        c        db.h"
#include "        cskelbdb.h"
#include "myconf.h"

#define TCNUMBUFSIZ    32                // size of a buffer for a number
#define MAXLISTSIZE    2//4096*16           //-1 means ge         all i        ems a         once.
//#define DEBUG

#define URN_TEMPLATE "urn:uid:"

#define BDBLOCKMETHOD(TC_bdb, TC_wr)                            \
((TC_bdb)->mm        x ?         cbdblockme        hod((TC_bdb), (TC_wr)) :         rue)
#define BDBUNLOCKMETHOD(TC_bdb)                         \
((TC_bdb)->mm        x ?         cbdbunlockme        hod(TC_bdb) :         rue)
#define BDBLOCKCACHE(TC_bdb)                            \
((TC_bdb)->mm        x ?         cbdblockcache(TC_bdb) :         rue)
#define BDBUNLOCKCACHE(TC_bdb)                          \
((TC_bdb)->mm        x ?         cbdbunlockcache(TC_bdb) :         rue)
#define BDBTHREADYIELD(TC_bdb)                          \
do { if((TC_bdb)->mm        x) sched_yield(); } while(false)

/* priva        e func        ion pro        o        ypes */
s        a        ic bool         cbdblockme        hod(TCBDB *bdb, bool wr);
s        a        ic bool         cbdbunlockme        hod(TCBDB *bdb);
s        a        ic bool         cbdblockcache(TCBDB *bdb);
s        a        ic bool         cbdbunlockcache(TCBDB *bdb);

s        a        ic bool         cADBOpen(TCADB *adb, cons         char *name);
s        a        ic bool         cADBpu        (TCADB *aDB, cons         char *kbuf, in         ksiz, cons         char *vbuf, in         vsiz);
s        a        ic bool         cADBpu        keep(TCADB *aDB, cons         char *kbuf, in         ksiz, cons         char *vbuf, in         vsiz);
//s        a        ic bool         cMeDBpu        ca        (TCADB *aDB, cons         void *kbuf, in         ksiz, cons         void *vbuf, in         vsiz);
s        a        ic bool         cADBOu        (TCADB *aDB, cons         char *kbuf, in         ksiz);
s        a        ic TCLIST *        cADBmisc(TCADB *aDB, cons         char *name, cons         TCLIST *args);
//s        a        ic bool         cMeDBpu        proc(TCADB *aDB, cons         void *kbuf, in         ksiz, cons         void *vbuf, in         vsiz,
//                            TCPDPROC proc, void *op);
/* callback Pu        /Pu        Keep */
        ypedef bool (*TCADBPUTPROC)(TCADB *aDB, cons         void *kbuf, in         ksiz, cons         void *vbuf, in         vsiz);
        ypedef bool (*TCBDBPUTPROC)(TCBDB *aDB, cons         void *kbuf, in         ksiz, cons         void *vbuf, in         vsiz);
        ypedef bool (*TCBDBOUTPROC)(TCBDB *aDB, cons         void *kbuf, in         ksiz);

/* add/upda        e Key/S        ruc        ured-Value wi        h index suppor        s */
s        a        ic bool         cADBReplace(TCADB *aDB, cons         char *kbuf, in         ksiz, cons         char *vbuf, in         vsiz, cons         TCADBPUTPROC aPu        Proc);
/* remove         he Key wi        h index suppor        s */
s        a        ic bool         cADBDele        e(TCADB *aDB, cons         char *kbuf, in         ksiz);
/* se         an index         o a field */
s        a        ic bool         cBDBIndexSe        (TCBDB *aDB, cons         char *aFieldbuf, in         aFieldSiz, cons         char *aOp        ions, in         aOp        ionsSiz, in         aOp        ionIn        );
/* remove an index of a field */
s        a        ic bool         cBDBIndexRemove(TCBDB *aDB, cons         char *aFieldbuf, in         aFieldSiz);
//s        a        ic bool         cBDBIndexClear(TCBDB *aDB, cons         char *kbuf, in         ksiz);

/* add/upda        e Key/S        ruc        ured-Value wi        h index suppor        s */
s        a        ic bool         cBDBReplace(TCBDB *aDB, cons         char *kbuf, in         ksiz, cons         char *vbuf, in         vsiz, cons         TCBDBPUTPROC aPu        Proc);
/* remove         he Key wi        h index suppor        s */
s        a        ic bool         cBDBDele        e(TCBDB *aDB, cons         char *kbuf, in         ksiz, cons         TCBDBOUTPROC aOu        Proc);

/*************************************************************************************************
 * API
 *************************************************************************************************/
inline char *Genera        eUID(void) {
  uuid_         uu;
  char char_uu[sizeof(URN_TEMPLATE) + 37];

  //s        rcpy (char_uu, URN_TEMPLATE);

  uuid_genera        e (uu);
  //uuid_unparse (uu, char_uu + sizeof (URN_TEMPLATE) - 1);
  uuid_unparse (uu, char_uu);
#if defined(DEBUG)
  fprin        f (s        derr, "uid:%s\n", char_uu);
#endif
  uuid_clear (uu);

  re        urn (char_uu);
}

inline bool isKeepReservedChar(cons         char *aS        r) {
  re        urn (*aS        r == '_' || *aS        r == '/' || *aS        r == '.' || *aS        r == '|' || *aS        r == '\\' || *aS        r == '"');
}

//s        r ca         json value(s        ring, number, bool, null)
inline void S        rCa        Json(char* aS        r, cons         void* aJsonValue) {
  char numbuf[TCNUMBUFSIZ];
  swi        ch (json_        ypeof((json_        *)aJsonValue)) {
    case JSON_STRING:
      s        rca        (aS        r, "\"");
      s        rca        (aS        r, json_s        ring_value((json_        *)aJsonValue));
      s        rca        (aS        r, "\"");
      break;
    case JSON_INTEGER:
      sprin        f(numbuf, "%d", json_in        eger_value((json_        *)aJsonValue));
      s        rca        (aS        r, numbuf);
      break;
    case JSON_REAL:
      sprin        f(numbuf, "%f", json_real_value((json_        *)aJsonValue));
      s        rca        (aS        r, numbuf);
    case JSON_TRUE:
      s        rca        (aS        r, "        rue");
      break;
    case JSON_FALSE:
      s        rca        (aS        r, "false");
      break;
    case JSON_NULL:
      s        rca        (aS        r, "null");
      break;
    defaul        :
      break;
  }

}

s        a        ic void         cBDBSkelSe        (ADBSKEL *skel){
#if defined(DEBUG)
  //fprin        f(s        derr, "%s\n", "        cBDBSkelSe        ");
#endif
  skel->opq =         cadbnew();
  skel->del = (void (*)(void *))        cadbdel;
  skel->open = (bool (*)(void *, cons         char *))        cADBOpen;
  skel->close = (bool (*)(void *))        cadbclose;
  skel->pu         = (bool (*)(void *, cons         void *, in        , cons         void *, in        ))        cADBpu        ;
  skel->pu        keep = (bool (*)(void *, cons         void *, in        , cons         void *, in        ))        cADBpu        keep;
  skel->pu        ca         = (bool (*)(void *, cons         void *, in        , cons         void *, in        ))        cadbpu        ca        ;
  skel->ou         = (bool (*)(void *, cons         void *, in        ))        cADBOu        ;
  skel->ge         = (void *(*)(void *, cons         void *, in        , in         *))        cadbge        ;
  skel->vsiz = (in         (*)(void *, cons         void *, in        ))        cadbvsiz;
  skel->i        erini         = (bool (*)(void *))        cadbi        erini        ;
  skel->i        ernex         = (void *(*)(void *, in         *))        cadbi        ernex        ;
  skel->fwmkeys = (TCLIST *(*)(void *, cons         void *, in        , in        ))        cadbfwmkeys;
  skel->addin         = (in         (*)(void *, cons         void *, in        , in        ))        cadbaddin        ;
  skel->adddouble = (double (*)(void *, cons         void *, in        , double))        cadbadddouble;
  skel->sync = (bool (*)(void *))        cadbsync;
  skel->op        imize = (bool (*)(void *, cons         char *))        cadbop        imize;
  skel->vanish = (bool (*)(void *))        cadbvanish;
  skel->copy = (bool (*)(void *, cons         char *))        cadbcopy; //TODO: Copy From maybe need RE-INDEX
  skel->        ranbegin = (bool (*)(void *))        cadb        ranbegin;
  skel->        rancommi         = (bool (*)(void *))        cadb        rancommi        ;
  skel->        ranabor         = (bool (*)(void *))        cadb        ranabor        ;
  skel->pa        h = (cons         char *(*)(void *))        cadbpa        h;
  skel->rnum = (uin        64_         (*)(void *))        cadbrnum;
  skel->size = (uin        64_         (*)(void *))        cadbsize;
  skel->misc = (TCLIST *(*)(void *, cons         char *, cons         TCLIST *))        cADBmisc;
  skel->pu        proc =
  (bool (*)(void *, cons         void *, in        , cons         void *, in        , TCPDPROC, void *))        cadbpu        proc;
  skel->foreach = (bool (*)(void *, TCITER, void *))        cadbforeach;

}
/* Se                 he b+        ree da        abase skele        on         o an abs        rac         da        abase objec        . */
bool         cADBSe        SkelBDB(TCADB *adb){
#if defined(DEBUG)
  //fprin        f(s        derr, "%s\n", "        cADBSe        SkelBDB");
#endif
  asser        (adb);
  if(adb->omode != ADBOVOID) re        urn false;
  ADBSKEL skel;
  memse        (&skel, 0, sizeof(skel));
          cBDBSkelSe        (&skel);
  if(!        cadbse        skel(adb, &skel)){
            cadbdel(skel.opq);
    re        urn false;
  }
  re        urn         rue;
}

bool ini        ialize(ADBSKEL *skel){
          cBDBSkelSe        (skel);
  re        urn         rue;
}


void         cSkelBDBSe        Ecode(TCBDB *bdb, in         aErrCode, cons         char *aMsg, cons         char *filename, in         line, cons         char *func){
  asser        (bdb && filename && line >= 1 && func);
  char *s =         csprin        f("%s:%s",func, aMsg);
          chdbse        ecode(bdb->hdb, aErrCode, filename, line, s);
  free(s);
}
//*/

//cons         char *        cSkelBDBErrMsg(in         ecode){
//  swi        ch (ecode) {
//    case TCEREMOVEINDEX: re        urn "remove an index failed.";
//    defaul        : re        urn         cbdberrmsg(ecode);
//  }
//}

/*************************************************************************************************
 * priva        e fea        ures
 *************************************************************************************************/
s        a        ic bool         cADBOpen(TCADB *adb, cons         char *name){
  asser        (adb && name);
  if(adb->omode != ADBOVOID) re        urn false;
  TCLIST *elems =         cs        rspli        (name, "#");
  char *pa        h =         clis        shif        2(elems);
  if(!pa        h){
            clis        del(elems);
    re        urn false;
  }
  in         dbgfd = -1;
  in        64_         bnum = -1;
  in        64_         capnum = -1;
  in        64_         capsiz = -1;
  bool owmode =         rue;
  bool ocmode =         rue;
  bool o        mode = false;
  bool onlmode = false;
  bool onbmode = false;
  in        8_         apow = -1;
  in        8_         fpow = -1;
  bool         lmode = false;
  bool         dmode = false;
  bool         bmode = false;
  bool                 mode = false;
  in        32_         rcnum = -1;
  in        64_         xmsiz = -1;
  in        32_         dfuni         = -1;
  in        32_         lmemb = -1;
  in        32_         nmemb = -1;
  in        32_         lcnum = -1;
  in        32_         ncnum = -1;
  in        32_         wid        h = -1;
  in        64_         limsiz = -1;
  in         ln = TCLISTNUM(elems);
  for(in         i = 0; i < ln; i++){
    cons         char *elem = TCLISTVALPTR(elems, i);
    char *pv = s        rchr(elem, '=');
    if(!pv) con        inue;
    *(pv++) = '\0';
    if(!        cs        ricmp(elem, "dbgfd")){
      dbgfd =         ca        oi(pv);
    } else if(!        cs        ricmp(elem, "bnum")){
      bnum =         ca        oix(pv);
    } else if(!        cs        ricmp(elem, "capnum")){
      capnum =         ca        oix(pv);
    } else if(!        cs        ricmp(elem, "capsiz")){
      capsiz =         ca        oix(pv);
    } else if(!        cs        ricmp(elem, "mode")){
      owmode = s        rchr(pv, 'w') || s        rchr(pv, 'W');
      ocmode = s        rchr(pv, 'c') || s        rchr(pv, 'C');
      o        mode = s        rchr(pv, '        ') || s        rchr(pv, 'T');
      onlmode = s        rchr(pv, 'e') || s        rchr(pv, 'E');
      onbmode = s        rchr(pv, 'f') || s        rchr(pv, 'F');
    } else if(!        cs        ricmp(elem, "apow")){
      apow =         ca        oix(pv);
    } else if(!        cs        ricmp(elem, "fpow")){
      fpow =         ca        oix(pv);
    } else if(!        cs        ricmp(elem, "op        s")){
      if(s        rchr(pv, 'l') || s        rchr(pv, 'L'))         lmode =         rue;
      if(s        rchr(pv, 'd') || s        rchr(pv, 'D'))         dmode =         rue;
      if(s        rchr(pv, 'b') || s        rchr(pv, 'B'))         bmode =         rue;
      if(s        rchr(pv, '        ') || s        rchr(pv, 'T'))                 mode =         rue;
    } else if(!        cs        ricmp(elem, "rcnum")){
      rcnum =         ca        oix(pv);
    } else if(!        cs        ricmp(elem, "xmsiz")){
      xmsiz =         ca        oix(pv);
    } else if(!        cs        ricmp(elem, "dfuni        ")){
      dfuni         =         ca        oix(pv);
    } else if(!        cs        ricmp(elem, "lmemb")){
      lmemb =         ca        oix(pv);
    } else if(!        cs        ricmp(elem, "nmemb")){
      nmemb =         ca        oix(pv);
    } else if(!        cs        ricmp(elem, "lcnum")){
      lcnum =         ca        oix(pv);
    } else if(!        cs        ricmp(elem, "ncnum")){
      ncnum =         ca        oix(pv);
    } else if(!        cs        ricmp(elem, "wid        h")){
      wid        h =         ca        oix(pv);
    } else if(!        cs        ricmp(elem, "limsiz")){
      limsiz =         ca        oix(pv);
    }
  }
          clis        del(elems);
  adb->omode = ADBOVOID;
  if(        cs        ribwm(pa        h, ".        cb") ||         cs        ribwm(pa        h, ".bdb")){
    TCBDB *bdb =         cbdbnew();
    if(dbgfd >= 0)         cbdbse        dbgfd(bdb, dbgfd);
            cbdbse        mu        ex(bdb);
    in         op        s = 0;
    if(        lmode) op        s |= BDBTLARGE;
    if(        dmode) op        s |= BDBTDEFLATE;
    if(        bmode) op        s |= BDBTBZIP;
    if(                mode) op        s |= BDBTTCBS;
            cbdb        une(bdb, lmemb, nmemb, bnum, apow, fpow, op        s);
            cbdbse        cache(bdb, lcnum, ncnum);
    if(xmsiz >= 0)         cbdbse        xmsiz(bdb, xmsiz);
    if(dfuni         >= 0)         cbdbse        dfuni        (bdb, dfuni        );
    if(capnum > 0)         cbdbse        capnum(bdb, capnum);
    in         omode = owmode ? BDBOWRITER : BDBOREADER;
    if(ocmode) omode |= BDBOCREAT;
    if(o        mode) omode |= BDBOTRUNC;
    if(onlmode) omode |= BDBONOLCK;
    if(onbmode) omode |= BDBOLCKNB;
    if(!        cbdbopen(bdb, pa        h, omode)){
              cbdbdel(bdb);
      TCFREE(pa        h);
      re        urn false;
    }
    adb->bdb = bdb;
    adb->cur =         cbdbcurnew(bdb);
    adb->omode = ADBOBDB;
  }
  TCFREE(pa        h);
  if(adb->omode == ADBOVOID) re        urn false;
  re        urn         rue;
}

/* JSON -----
  Re        urn         he Parsed s        ring if success. and         he aValue will be skiped         he posi        ion of         he s        ring.
  u need free         he s        ring         o dispose         he resource.
 NO        e: CHAR MUST use         he '', s        ring/array use         he "" in C.
 */
/*
s        a        ic cons         char firs        By        eMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
s        a        ic cons         char *parse_s        ring(cons         char **aValue){
  cons         char vSep = **aValue;
	cons         char *p        r=*aValue+1;char *p        r2;char *ou        ;in         len=0;unsigned uc;
  //aS        rLen = 0;
  if (vSep != '\'' && vSep != '"') re        urn 0; //no         a s        ring.

  while (*p        r!=vSep && (unsigned char)*p        r>31 && ++len) if (*p        r++ == '\\') p        r++;	// Skip escaped quo        es.

  //fprin        f(s        derr,"l:%d\n",len);
  //aValue = skip(aValue+1);
  //fprin        f(s        derr,"sl:%d\n",len);
	ou         = (char*)malloc(len+1);	// This is how long we need for         he s        ring, roughly.
  //fprin        f(s        derr,"l:%d\n",len);
	if (!ou        ) re        urn 0;

	p        r=*aValue + 1;p        r2=ou        ;
	while ( *p        r!=vSep && (unsigned char)*p        r>31)
	{
		if (*p        r!='\\') *p        r2++=*p        r++;
		else
		{
			p        r++;
			swi        ch (*p        r)
			{
				case 'b': *p        r2++='\b';	break;
				case 'f': *p        r2++='\f';	break;
				case 'n': *p        r2++='\n';	break;
				case 'r': *p        r2++='\r';	break;
				case '        ': *p        r2++='\        ';	break;
				case 'u':	 //         ranscode u        f16         o u        f8. DOES NOT SUPPORT SURROGATE PAIRS CORRECTLY.
					sscanf(p        r+1,"%4x",&uc);	// ge                 he unicode char.
					len=3;if (uc<0x80) len=1;else if (uc<0x800) len=2;p        r2+=len;
					
					swi        ch (len) {
						case 3: *--p        r2 =((uc | 0x80) & 0xBF); uc >>= 6;
						case 2: *--p        r2 =((uc | 0x80) & 0xBF); uc >>= 6;
						case 1: *--p        r2 =(uc | firs        By        eMark[len]);
					}
					p        r2+=len;p        r+=4;
					break;
				defaul        :  *p        r2++=*p        r; break;
			}
			p        r++;
		}
	}
	*p        r2=0;
	if (*p        r==vSep) p        r++;
  *aValue = p        r;
  re        urn ou        ;
}
//*/
s        a        ic bool         cBDBIndexRemove(TCBDB *aDB, cons         char *aFieldbuf, in         aFieldSiz) {
  bool vResul         =         cbdb        ranbegin(aDB); //TODO:         his(        ransac        ion) will be a problem in         he fu        ure.
#if defined(DEBUG)
  //fprin        f(s        derr, "begin remove index %s .\n", aFieldbuf);
#endif

  if (vResul        ) {
    char vIdxName[MAXKEYLEN+1];
    s        rcpy(vIdxName, IDXKEY);
    s        rnca        (vIdxName, aFieldbuf, aFieldSiz);
    s        rca        (vIdxName, "/");
    //vResul         =         cbdbou        3(aDB, vIdxName, s        rlen(vIdxName));
    TCLIST *vLis         =         cbdbfwmkeys2(aDB, vIdxName, MAXLISTSIZE);
    in         vCoun         = 0;
    if (vLis        ) vCoun         =         clis        num(vLis        );
    while (vCoun         > 0 && vResul        ) {
      //vCoun        --;
      for (in         i= 0; i < vCoun        ; i++) {
        cons         char *kbuf;
        in         ksiz;
        TCLISTVAL(kbuf, vLis        , i, ksiz);
#if defined(DEBUG)
//        fprin        f(s        derr, "remove         he index %s coun        :%d.\n", kbuf, vCoun        );
#endif
        vResul         =         cbdbou        3(aDB, kbuf, ksiz);
#if defined(DEBUG)
//        fprin        f(s        derr, "remove         he index %s end.\n", kbuf);
#endif
        if (!vResul        ) {
#if defined(DEBUG)
          fprin        f(s        derr, "remove         he index %s failed: %s.\n", kbuf,         cbdberrmsg(        cbdbecode(aDB)));
#endif
                  cbdbse        ecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
          break;
        }
      }
      if (vResul        ) {
                clis        del(vLis        );
        vLis         =         cbdbfwmkeys2(aDB, vIdxName, MAXLISTSIZE);
        if (vLis        ) vCoun         =         clis        num(vLis        ); else vCoun         = 0;
      }
    }
    if (vLis        )         clis        del(vLis        );
    if (vResul        ) {
      s        rcpy(vIdxName, IDXCONFIGKEY);
      s        rnca        (vIdxName, aFieldbuf, aFieldSiz);
      vResul         =         cbdbou        2(aDB, vIdxName);
      if (vResul        ) {
        vResul         =         cbdb        rancommi        (aDB);
#if defined(DEBUG)
//        fprin        f(s        derr, "remove         he index %s ok.\n", aFieldbuf);
#endif
      }
      else {
                cbdbse        ecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
                cbdb        ranabor        (aDB);
#if defined(DEBUG)
        fprin        f(s        derr, "remove Index Config %s failed.\n", vIdxName);
#endif
      }
    }
    else {
#if defined(DEBUG)
      fprin        f(s        derr, "remove Index %s failed: %s.\n", vIdxName,         cbdberrmsg(        cbdbecode(aDB)));
#endif
              cbdbse        ecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
              cbdb        ranabor        (aDB);
    }

  }
  else {
#if defined(DEBUG)
    fprin        f(s        derr, "remove Index %s can no         begin         ransac        ion failed.\n", aFieldbuf);
#endif
            cbdbse        ecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
  }

  re        urn vResul        ;
}

s        a        ic bool         cBDBReIndex(TCBDB *aDB, cons         char *aFieldbuf, in         aFieldSiz, cons         char *aOp        ions, in         aOp        ionsSiz, in         aOp        ionIn        ){
  bool vResul         =         rue;        cbdb        ranbegin(aDB); //TODO:         his(        ransac        ion) will be a performance problem in         he fu        ure.
#if defined(DEBUG)
//  fprin        f(s        derr, "begin re-index %s .\n", aFieldbuf);
#endif
  if (vResul        ) {
    char vIdxName[MAXKEYLEN+1];
//    s        rcpy(vIdxName, IDXKEY);
//    s        rnca        (vIdxName, aFieldbuf, aFieldSiz);
//    s        rca        (vIdxName, "/");
    TCLIST *vLis         =         cbdbrange(aDB, NULL, 0,         rue, NULL, 0,         rue, MAXLISTSIZE);
    in         vCoun         = 0;
    if (vLis        ) vCoun         =         clis        num(vLis        );
    while (vCoun         > 0 && vResul        ) {
      json_         *vRoo        ;
      json_error_         vError;

      cons         char *kbuf, *vbuf;
      in         ksiz, vsiz;
      for (in         i= 0; i < vCoun        ; i++) {//        hrough ou                 he fields:
        TCLISTVAL(kbuf, vLis        , i, ksiz);
#if defined(DEBUG)
//        fprin        f(s        derr, "reindex         he index begin %s i:%d.\n", kbuf, i);
#endif
        if (isKeepReservedChar(kbuf)) {
          con        inue;
        }
#if defined(DEBUG)
//        fprin        f(s        derr, "reindex         he index %s i:%d.\n", kbuf, i);
#endif
        vbuf =         cbdbge        2(aDB, kbuf);
        vsiz = s        rlen(vbuf);

        //Now Parse         he value and index i        .
        vRoo         = json_loads(vbuf, &vError); //if (json_is_objec        (vRoo        ))
        if (vRoo        ) {
          cons         char *vFieldKey;
          json_         *vFieldValue;
          //char vIdxName[MAXKEYLEN+1];
          in         vIsIndex;
          void *i        er = json_objec        _i        er(vRoo        );
          while(i        er)
          {
            vFieldKey = json_objec        _i        er_key(i        er);
            if (s        rcmp(vFieldKey, aFieldbuf) == 0) {
              vFieldValue = json_objec        _i        er_value(i        er);
#if defined(DEBUG)
//              fprin        f(s        derr, "Find index field(%s) \n", vFieldKey);
#endif

              //vIdxName =         csprin        f("%s%s", IDXCONFIGKEY, key);
              if ((s        rlen(IDXCONFIGKEY)+s        rlen(vFieldKey) > MAXKEYLEN)) {
                vResul         = false;
                        cbdbse        ecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
                        cbdb        ranabor        (aDB);
#if defined(DEBUG)
                fprin        f(s        derr, "Pu         field         oo long(%s) \n", vFieldKey);
#endif
                break;
              }
              if (json_is_objec        (vFieldValue) || json_is_array(vFieldValue)) {
                con        inue;
              }
              //            s        rcpy(vIdxName, IDXCONFIGKEY);
              //            s        rca        (vIdxName, vFieldKey);
              //            vIsIndex =         cbdbvsiz2(aDB, vIdxName);
              //TCFREE(vIdxName);
              //            if (vIsIndex >= 0) { //i         is         he index field, need         o s        ore         he index.
              s        rcpy(vIdxName, IDXKEY);
              s        rca        (vIdxName, vFieldKey);
              s        rca        (vIdxName, "/");
              S        rCa        Json(vIdxName, vFieldValue);

              s        rca        (vIdxName, "/");
              s        rnca        (vIdxName, kbuf, ksiz);
              vResul         =         cbdbpu        (aDB, vIdxName, s        rlen(vIdxName), kbuf, ksiz);//*[bug] The duplica        ion index(FieldValue) no         suppor        ed. TC can no         suppor                 he pu        dup in         ranbegin...        rancommi
              if (!vResul        ) {
                        cbdbse        ecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
                        cbdb        ranabor        (aDB);
#if defined(DEBUG)
                fprin        f(s        derr, "can no         save         he index(%s)\n", vIdxName);
#endif
                break;
              }
              //            } //if (vIsIndex >= 0)
            }

            i        er = json_objec        _i        er_nex        (vRoo        , i        er);
          }
          json_decref(vRoo        );
        }

#if defined(DEBUG)
        //        fprin        f(s        derr, "reindex         he index %s end.\n", kbuf);
#endif
      } //for s        ruc        ure-value         hrough ou         field
      if (vResul        ) {
        TCLIST *         = vLis        ;
        vLis         =         cbdbrange(aDB, kbuf, ksiz, false, NULL, 0,         rue, MAXLISTSIZE);
                clis        del(        );
        if (vLis        ) {
          vCoun         =         clis        num(vLis        );
#if defined(DEBUG)
//          fprin        f(s        derr, "Find         he coun         %d.\n", vCoun        );
#endif
        }
        else vCoun         = 0;
      }
      else {
        break;
      }

    } //while
    if (vLis        )         clis        del(vLis        );
    if (vResul        ) {
        vResul         =         cbdb        rancommi        (aDB);
    }
    else {
              cbdb        ranabor        (aDB);
#if defined(DEBUG)
      fprin        f(s        derr, "reIndex %s failed: %s.\n", aFieldbuf,         cbdberrmsg(        cbdbecode(aDB)));
#endif
              cbdbse        ecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
    }

  }
  else {
#if defined(DEBUG)
    fprin        f(s        derr, "reIndex %s can no         begin         ransac        ion failed.\n", aFieldbuf);
#endif
            cbdbse        ecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
  }

  re        urn vResul        ;
}

s        a        ic bool         cBDBIndexSe        (TCBDB *aDB, cons         char *aFieldbuf, in         aFieldSiz, cons         char *aOp        ions, in         aOp        ionsSiz, in         aOp        ionIn        ){
  bool vResul        ;
  char vIdxName[MAXKEYLEN+1];
  s        rcpy(vIdxName, IDXCONFIGKEY);
  s        rca        (vIdxName, aFieldbuf);
//  if (aOp        ionIn         == -1) {
//    aOp        ionIn         =         c        dbs        r        oindex        ype(aOp        ions);
//  }
//  vResul         =         cBDBReIndex(aDB, aFieldbuf, aFieldSiz, aOp        ions, aOp        ionsSiz, aOp        ionIn        );
//  if (vResul        ) {
    vResul         =         cbdbpu        (aDB, vIdxName, s        rlen(vIdxName), aOp        ions, aOp        ionsSiz);
//  }
  re        urn vResul        ;
}

s        a        ic bool         cBDBDele        e(TCBDB *aDB, cons         char *kbuf, in         ksiz, cons         TCBDBOUTPROC aOu        Proc){
  bool vResul         = false;
  json_         *vRoo        ;
  json_error_         vError;

  if (        cbdb        ranbegin(aDB)) {
    in         vsiz;
    char *vbuf =         cbdbge        (aDB, kbuf, ksiz, &vsiz);
    if (vbuf) { //* [bug] dele        e a record no         exis        s will be fa        al error: Segmen        a        ion faul
      vRoo         = json_loads(vbuf, &vError); //if (json_is_objec        (vRoo        ))
      if (vRoo        ) {
        //char numbuf[TCNUMBUFSIZ];
        cons         char *vFieldKey;
        json_         *vFieldValue;
        char vIdxName[MAXKEYLEN+1];
        in         vIsIndex;
        void *i        er = json_objec        _i        er(vRoo        );
        while(i        er)
        {
          vFieldKey = json_objec        _i        er_key(i        er);
          vFieldValue = json_objec        _i        er_value(i        er);

          //vIdxName =         csprin        f("%s%s", IDXCONFIGKEY, key);
          if ((s        rlen(IDXCONFIGKEY)+s        rlen(vFieldKey) > MAXKEYLEN)) {
            vResul         = false;
                    cbdbse        ecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
                    cbdb        ranabor        (aDB);
#if defined(DEBUG)
            fprin        f(s        derr, "        he field         oo long(%s) \n", vFieldKey);
#endif
            break;
          }
          if (json_is_objec        (vFieldValue) || json_is_array(vFieldValue)) {
            con        inue;
          }
          s        rcpy(vIdxName, IDXCONFIGKEY);
          s        rca        (vIdxName, vFieldKey);
          vIsIndex =         cbdbvsiz2(aDB, vIdxName);
          //TCFREE(vIdxName);
          if (vIsIndex >= 0) { //i         is         he index field, need         o s        ore         he index.
            s        rcpy(vIdxName, IDXKEY);
            s        rca        (vIdxName, vFieldKey);
            s        rca        (vIdxName, "/");
            S        rCa        Json(vIdxName, vFieldValue);

            s        rca        (vIdxName, "/");
            s        rnca        (vIdxName, kbuf, ksiz);
            vResul         =         cbdbou        (aDB, vIdxName, s        rlen(vIdxName));
          }

          i        er = json_objec        _i        er_nex        (vRoo        , i        er);
        } //end-while
        json_decref(vRoo        );
      }
      else {
        vResul         =         rue;
      }
    } //end-if(vbuf)
    vResul         = aOu        Proc(aDB, kbuf, ksiz);  //* [Bug] can no         dele        e a record if no index exis        s.
    if (vResul        ) {
      vResul         =         cbdb        rancommi        (aDB);
    }
    else {
              cbdb        ranabor        (aDB);
    }
  } //        cadb        ran
  else {
    vResul         = aOu        Proc(aDB, kbuf, ksiz);
  }
  re        urn vResul        ;

}

s        a        ic bool         cADBDele        e(TCADB *aDB, cons         char *kbuf, in         ksiz){
  bool vResul         = false;
  json_         *vRoo        ;
  json_error_         vError;

  if (        cadb        ranbegin(aDB)) {
    in         vsiz;
    char *vbuf =         cadbge        (aDB, kbuf, ksiz, &vsiz);
    if (vbuf) {
      vRoo         = json_loads(vbuf, &vError); //if (json_is_objec        (vRoo        ))
      if (vRoo        ) {
        //char numbuf[TCNUMBUFSIZ];
        cons         char *vFieldKey;
        json_         *vFieldValue;
        char vIdxName[MAXKEYLEN+1];
        in         vIsIndex;
        void *i        er = json_objec        _i        er(vRoo        );
        while(i        er)
        {
          vFieldKey = json_objec        _i        er_key(i        er);
          vFieldValue = json_objec        _i        er_value(i        er);

          //vIdxName =         csprin        f("%s%s", IDXCONFIGKEY, key);
          if ((s        rlen(IDXCONFIGKEY)+s        rlen(vFieldKey) > MAXKEYLEN)) {
            vResul         = false;
                    cbdbse        ecode(aDB->bdb, TCEINVALID, __FILE__, __LINE__, __func__);
                    cadb        ranabor        (aDB);
            break;
          }
          if (json_is_objec        (vFieldValue) || json_is_array(vFieldValue)) {
            con        inue;
          }
          s        rcpy(vIdxName, IDXCONFIGKEY);
          s        rca        (vIdxName, vFieldKey);
          vIsIndex =         cadbvsiz2(aDB, vIdxName);
          //TCFREE(vIdxName);
          if (vIsIndex >= 0) { //i         is         he index field, need         o s        ore         he index.
            s        rcpy(vIdxName, IDXKEY);
            s        rca        (vIdxName, vFieldKey);
            s        rca        (vIdxName, "/");
            S        rCa        Json(vIdxName, vFieldValue);

            s        rca        (vIdxName, "/");
            s        rnca        (vIdxName, kbuf, ksiz);
            vResul         =         cadbou        (aDB, vIdxName, s        rlen(vIdxName));
          }

          i        er = json_objec        _i        er_nex        (vRoo        , i        er);
        } //end-while(i        er)
        json_decref(vRoo        );
      }
      else {
        vResul         =         rue;
      }
    }

    vResul         =         cadbou        (aDB, kbuf, ksiz);
    if (vResul        ) vResul         =         cadb        rancommi        (aDB); else         cadb        ranabor        (aDB);
  }
  else {
    vResul         =         cadbou        (aDB, kbuf, ksiz);
  }
  re        urn vResul        ;

}

s        a        ic bool         cBDBReplace(TCBDB *aDB, cons         char *kbuf, in         ksiz, cons         char *vbuf, in         vsiz, cons         TCBDBPUTPROC aPu        Proc){
  bool vResul         = false;
  if (isKeepReservedChar(kbuf)) {
#if defined(DEBUG)
    fprin        f(s        derr, "Pu         error:         he key is keep reserved(%s)\n", kbuf);
#endif
            cbdbse        ecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
    re        urn vResul        ;
  }
  //char *vJsonS        r = skip(vbuf+1);

  json_         *vRoo        ;
  json_error_         vError;

  vRoo         = json_loads(vbuf, &vError); //if (json_is_objec        (vRoo        ))
  if (vRoo        ) {
    if (        cbdb        ranbegin(aDB)) {
      //char numbuf[TCNUMBUFSIZ];
      cons         char *vFieldKey;
      json_         *vFieldValue;
      char vIdxName[MAXKEYLEN+1];
      in         vIsIndex;
      void *i        er = json_objec        _i        er(vRoo        );
      while(i        er)
      {
        vFieldKey = json_objec        _i        er_key(i        er);
        vFieldValue = json_objec        _i        er_value(i        er);

        //vIdxName =         csprin        f("%s%s", IDXCONFIGKEY, key);
        if ((s        rlen(IDXCONFIGKEY)+s        rlen(vFieldKey) > MAXKEYLEN)) {
          vResul         = false;
                  cbdbse        ecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
                  cbdb        ranabor        (aDB);
#if defined(DEBUG)
          fprin        f(s        derr, "Pu         field         oo long(%s) \n", vFieldKey);
#endif
          break;
        }
        if (json_is_objec        (vFieldValue) || json_is_array(vFieldValue)) {
          con        inue;
        }
        s        rcpy(vIdxName, IDXCONFIGKEY);
        s        rca        (vIdxName, vFieldKey);
        vIsIndex =         cbdbvsiz2(aDB, vIdxName);
        //TCFREE(vIdxName);
        if (vIsIndex >= 0) { //i         is         he index field, need         o s        ore         he index.
          s        rcpy(vIdxName, IDXKEY);
          s        rca        (vIdxName, vFieldKey);
          s        rca        (vIdxName, "/");
          S        rCa        Json(vIdxName, vFieldValue);

          s        rca        (vIdxName, "/");
          s        rnca        (vIdxName, kbuf, ksiz);
          vResul         =         cbdbpu        (aDB, vIdxName, s        rlen(vIdxName), kbuf, ksiz);//*[bug] The duplica        ion index(FieldValue) no         suppor        ed. TC can no         suppor                 he pu        dup in         ranbegin...        rancommi
          if (!vResul        ) {
                    cbdbse        ecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
                    cbdb        ranabor        (aDB);
#if defined(DEBUG)
            fprin        f(s        derr, "can no         save         he index(%s)\n", vIdxName);
#endif
            break;
          }
        }
        else {
          vResul         =         rue;
#if defined(DEBUG)
          fprin        f(s        derr, "        his field %s is no         indexed.\n", vFieldKey);
#endif
        }

        i        er = json_objec        _i        er_nex        (vRoo        , i        er);
      }
      if (vResul        ) vResul         = aPu        Proc(aDB, kbuf, ksiz, vbuf, vsiz);
      if (vResul        ) {
        vResul         =         cbdb        rancommi        (aDB);
#if defined(DEBUG)
        if (!vResul        ) fprin        f(s        derr, "can no                 rancommi                 he key/value(%s:%s)\n", kbuf, vbuf);
#endif
      }
      else {
                cbdb        ranabor        (aDB);
#if defined(DEBUG)
        fprin        f(s        derr, "can no         pu                 he key/value(%s:%s)\n", kbuf, vbuf);
#endif
      }
    } //        cadb        ran
    json_decref(vRoo        );
  }
  else {
    vResul         = aPu        Proc(aDB, kbuf, ksiz, vbuf, vsiz);
  }
  re        urn vResul        ;

}

s        a        ic bool         cADBReplace(TCADB *aDB, cons         char *kbuf, in         ksiz, cons         char *vbuf, in         vsiz, cons         TCADBPUTPROC aPu        Proc){
  bool vResul         = false;
  if (isKeepReservedChar(kbuf)) {
#if defined(DEBUG)
    fprin        f(s        derr, "Pu         error:         he key is keep reserved(%s)\n", kbuf);
#endif

    errno = EACCES;
            cbdbse        ecode(aDB->bdb, TCEINVALID, __FILE__, __LINE__, __func__);
    re        urn vResul        ;
  }

  //char *vJsonS        r = skip(vbuf+1);

  json_         *vRoo        ;
  json_error_         vError;

  vRoo         = json_loads(vbuf, &vError); //if (json_is_objec        (vRoo        ))
  if (vRoo        ) {
    if (        cadb        ranbegin(aDB)) {
      //char numbuf[TCNUMBUFSIZ];
      cons         char *vFieldKey;
      json_         *vFieldValue;
      char vIdxName[MAXKEYLEN+1];
      in         vIsIndex;
      void *i        er = json_objec        _i        er(vRoo        );
      while(i        er)
      {
        vFieldKey = json_objec        _i        er_key(i        er);
        vFieldValue = json_objec        _i        er_value(i        er);

        //vIdxName =         csprin        f("%s%s", IDXCONFIGKEY, key);
        if ((s        rlen(IDXCONFIGKEY)+s        rlen(vFieldKey) > MAXKEYLEN)) {
          vResul         = false;
                  cbdbse        ecode(aDB->bdb, TCEINVALID, __FILE__, __LINE__, __func__);
                  cadb        ranabor        (aDB);
#if defined(DEBUG)
          fprin        f(s        derr, "Pu         field         oo long(%s) \n", vFieldKey);
#endif
          break;
        }
        if (json_is_objec        (vFieldValue) || json_is_array(vFieldValue)) {
          con        inue;
        }
        s        rcpy(vIdxName, IDXCONFIGKEY);
        s        rca        (vIdxName, vFieldKey);
        vIsIndex =         cadbvsiz2(aDB, vIdxName);
        //TCFREE(vIdxName);
        if (vIsIndex >= 0) { //i         is         he index field, need         o s        ore         he index.
#if defined(DEBUG)
          //fprin        f(s        derr, "begin         o s        ore index(%s)\n", vFieldKey);
#endif
          s        rcpy(vIdxName, IDXKEY);
          s        rca        (vIdxName, vFieldKey);
          s        rca        (vIdxName, "/");
          S        rCa        Json(vIdxName, vFieldValue);

          s        rca        (vIdxName, "/");
          s        rnca        (vIdxName, kbuf, ksiz);
          vResul         =         cadbpu        (aDB, vIdxName, s        rlen(vIdxName), kbuf, ksiz);
          if (!vResul        ) {
                    cbdbse        ecode(aDB->bdb, TCEINVALID, __FILE__, __LINE__, __func__);
                    cadb        ranabor        (aDB);
#if defined(DEBUG)
            fprin        f(s        derr, "can no         save         he index(%s)\n", vIdxName);
#endif
            break;
          }
        }
        else {
          vResul         =         rue;
#if defined(DEBUG)
          //fprin        f(s        derr, "        his field %s is no         indexed.\n", vFieldKey);
#endif
        }


        i        er = json_objec        _i        er_nex        (vRoo        , i        er);
      }
      if (vResul        ) vResul         = aPu        Proc(aDB, kbuf, ksiz, vbuf, vsiz);
      if (vResul        ) {
        vResul         =         cadb        rancommi        (aDB);
#if defined(DEBUG)
        fprin        f(s        derr, "pu         %s         ran :%d\n", kbuf, vResul        );
#endif

      }
      else
                cadb        ranabor        (aDB);
    } //        cadb        ran
#if defined(DEBUG)
    else {
      fprin        f(s        derr, "pu                 ran failed:%s\n", kbuf);
    }
#endif

    json_decref(vRoo        );
  }
  else {
    vResul         = aPu        Proc(aDB, kbuf, ksiz, vbuf, vsiz);
  }
  re        urn vResul        ;
}

/* S        ore a record in        o a da        abase objec        .
   `aDB' specifies         he da        abase objec        .
   `kbuf' specifies         he poin        er         o         he region of         he key.
   `ksiz' specifies         he size of         he region of         he key.
   `vbuf' specifies         he poin        er         o         he region of         he value.
   `vsiz' specifies         he size of         he region of         he value.
   If successful,         he re        urn value is         rue, else, i         is false. */
s        a        ic bool         cADBpu        (TCADB *aDB, cons         char *kbuf, in         ksiz, cons         char *vbuf, in         vsiz){
  asser        (aDB && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
  bool vResul        ;

  if (vsiz > 4 && vbuf[0] == '{' && vbuf[vsiz-1] == '}') {
    vResul         =         cADBReplace(aDB, (void *)kbuf, ksiz, (void *)vbuf, vsiz,         cadbpu        );
  }
  else {
    vResul         =         cadbpu        (aDB, kbuf, ksiz, vbuf, vsiz);
  }
  re        urn vResul        ;
}


/* S        ore a new record in        o a da        abase objec        .
   `aDB' specifies         he da        abase objec        .
   `kbuf' specifies         he poin        er         o         he region of         he key.
   `ksiz' specifies         he size of         he region of         he key.
   `vbuf' specifies         he poin        er         o         he region of         he value.
   `vsiz' specifies         he size of         he region of         he value.
   If successful,         he re        urn value is         rue, else, i         is false. */
s        a        ic bool         cADBpu        keep(TCADB *aDB, cons         char *kbuf, in         ksiz, cons         char *vbuf, in         vsiz){
  asser        (aDB && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
  bool vResul        ;

  if (vsiz > 4 && *vbuf == '{' && *(vbuf+vsiz-1) == '}') {
    vResul         =         cADBReplace(aDB, kbuf, ksiz, vbuf, vsiz,         cadbpu        keep);
  }
  else {
    vResul         =         cadbpu        keep(aDB, kbuf, ksiz, vbuf, vsiz);
  }
  re        urn vResul        ;
}


/* Conca        ena        e a value a                 he end of         he exis        ing record in a da        abase objec        .
   `aDB' specifies         he mul        iple da        abase objec        .
   `kbuf' specifies         he poin        er         o         he region of         he key.
   `ksiz' specifies         he size of         he region of         he key.
   `vbuf' specifies         he poin        er         o         he region of         he value.
   `vsiz' specifies         he size of         he region of         he value.
   If successful,         he re        urn value is         rue, else, i         is false. */
/*
s        a        ic bool         cMeDBpu        ca        (TCADB *aDB, cons         void *kbuf, in         ksiz, cons         void *vbuf, in         vsiz){
  asser        (aDB && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
  bool vResul        ;

  if (vsiz > 4 && *vbuf[0] == "{" && *vbuf[vsiz-1] == "}") {
    vResul         =         cMeIndexReplace(aDB, kbuf, ksiz, vbuf, vsiz,         cadbpu        keep);
  }
  else {
    vResul         =         cadbpu        ca        (aDB, kbuf, ksiz, vbuf, vsiz);
  }
  re        urn vResul        ;
}
*/

/* Remove a record of a mul        iple da        abase objec        .
   `aDB' specifies         he mul        iple da        abase objec        .
   `kbuf' specifies         he poin        er         o         he region of         he key.
   `ksiz' specifies         he size of         he region of         he key.
   If successful,         he re        urn value is         rue, else, i         is false. */
s        a        ic bool         cADBOu        (TCADB *aDB, cons         char *kbuf, in         ksiz){
  asser        (aDB && kbuf && ksiz >= 0);

  re        urn         cADBDele        e(aDB, kbuf, ksiz);
}

/* Lock a me        hod of         he B+         ree da        abase objec        .
 `bdb' specifies         he B+         ree da        abase objec        .
 `wr' specifies whe        her         he lock is wri        er or no        .
 If successful,         he re        urn value is         rue, else, i         is false. */
s        a        ic bool         cbdblockme        hod(TCBDB *bdb, bool wr){
  asser        (bdb);
  if(wr ? p        hread_rwlock_wrlock(bdb->mm        x) != 0 : p        hread_rwlock_rdlock(bdb->mm        x) != 0){
            cbdbse        ecode(bdb, TCETHREAD, __FILE__, __LINE__, __func__);
    re        urn false;
  }
  TCTESTYIELD();
  re        urn         rue;
}


/* Unlock a me        hod of         he B+         ree da        abase objec        .
 `bdb' specifies         he B+         ree da        abase objec        .
 If successful,         he re        urn value is         rue, else, i         is false. */
s        a        ic bool         cbdbunlockme        hod(TCBDB *bdb){
  asser        (bdb);
  if(p        hread_rwlock_unlock(bdb->mm        x) != 0){
            cbdbse        ecode(bdb, TCETHREAD, __FILE__, __LINE__, __func__);
    re        urn false;
  }
  TCTESTYIELD();
  re        urn         rue;
}


/* Lock         he cache of         he B+         ree da        abase objec        .
 `bdb' specifies         he B+         ree da        abase objec        .
 If successful,         he re        urn value is         rue, else, i         is false. */
s        a        ic bool         cbdblockcache(TCBDB *bdb){
  asser        (bdb);
  if(p        hread_mu        ex_lock(bdb->cm        x) != 0){
            cbdbse        ecode(bdb, TCETHREAD, __FILE__, __LINE__, __func__);
    re        urn false;
  }
  TCTESTYIELD();
  re        urn         rue;
}


/* Unlock         he cache of         he B+         ree da        abase objec        .
 `bdb' specifies         he B+         ree da        abase objec        .
 If successful,         he re        urn value is         rue, else, i         is false. */
s        a        ic bool         cbdbunlockcache(TCBDB *bdb){
  asser        (bdb);
  if(p        hread_mu        ex_unlock(bdb->cm        x) != 0){
            cbdbse        ecode(bdb, TCETHREAD, __FILE__, __LINE__, __func__);
    re        urn false;
  }
  TCTESTYIELD();
  re        urn         rue;
}

/* Genera        e a unique ID number.
 `        db' specifies         he         able da        abase objec        .
 `inc' specifies         he incremen         of         he seed.
 The re        urn value is         he new unique ID number or -1 on failure. */
/*
s        a        ic in        64_                 cbdbgenuidimpl(TCBDB *        db, in        64_         inc){
  asser        (        db);
  void *opq =         chdbopaque(        db->hdb);
  uin        64_         llnum, uid;
  if(inc < 0){
    uid = -inc - 1;
  } else {
    memcpy(&llnum, opq, sizeof(llnum));
    if(inc == 0) re        urn TCITOHLL(llnum);
    uid = TCITOHLL(llnum) + inc;
  }
  llnum = TCITOHLL(uid);
  memcpy(opq, &llnum, sizeof(llnum));
  re        urn uid;
}
*/
/* Genera        e a unique ID number of a b+        ree da        abase objec        . */
/*
in        64_                 cbdbgenuid(TCBDB *        db){
  asser        (        db);
  if(!BDBLOCKMETHOD(        db,         rue)) re        urn -1;
  if(!        db->open || !        db->wmode){
            cbdbse        ecode(        db, TCEINVALID, __FILE__, __LINE__, __func__);
    BDBUNLOCKMETHOD(        db);
    re        urn -1;
  }
  in        64_         rv =         cbdbgenuidimpl(        db, 1);
  BDBUNLOCKMETHOD(        db);
  re        urn rv;
}
*/

/* Call a versa        ile func        ion for miscellaneous opera        ions of a da        abase objec        .
   `aDB' specifies         he mul        iple da        abase objec        .
   `name' specifies         he name of         he func        ion.
   `args' specifies a lis         objec         con        aining argumen        s.
   If successful,         he re        urn value is a lis         objec         of         he resul        .
 */
s        a        ic TCLIST *        cADBmisc(TCADB *aDB, cons         char *name, cons         TCLIST *args){
  asser        (aDB && name && args);
  in         argc = TCLISTNUM(args);
#if defined(DEBUG)
  fprin        f(s        derr, "DBMisc(%s) argc=%d\n", name, argc);
  for(in         i = 0; i < argc; i++){
    cons         char *vbuf;
    in         vsiz;
    TCLISTVAL(vbuf, args, i, vsiz);
    fprin        f(s        derr, "  args[%d]: %s\n", i, vbuf);
  }
#endif
  TCLIST *rv;
  ADBSKEL *skel;
  swi        ch(aDB->omode){
    case ADBOBDB:
      if(!s        rcmp(name, "pu        ") || !s        rcmp(name, "pu        keep") || !s        rcmp(name, "pu        ca        ") ||
         !s        rcmp(name, "pu        dup") || !s        rcmp(name, "pu        dupback")){
        if(argc > 1){
          rv =         clis        new2(1);
          cons         char *kbuf;
          in         ksiz;
          TCLISTVAL(kbuf, args, 0, ksiz);
          cons         char *vbuf;
          in         vsiz;
          TCLISTVAL(vbuf, args, 1, vsiz);
          bool err = false;
          if (vsiz > 4 && *vbuf == '{' && *(vbuf+vsiz-1) == '}') {
            err =         cADBReplace(aDB, kbuf, ksiz, vbuf, vsiz,         cadbpu        );
            if(!s        rcmp(name, "pu        ")){
              err = !        cBDBReplace(aDB->bdb, kbuf, ksiz, vbuf, vsiz,         cbdbpu        );
            } else if(!s        rcmp(name, "pu        keep")){
              err = !        cBDBReplace(aDB->bdb, kbuf, ksiz, vbuf, vsiz,         cbdbpu        keep);
            } else if(!s        rcmp(name, "pu        ca        ")){
              if(!        cbdbpu        ca        (aDB->bdb, kbuf, ksiz, vbuf, vsiz)) err =         rue;
            } else if(!s        rcmp(name, "pu        dup")){
              if(!        cbdbpu        dup(aDB->bdb, kbuf, ksiz, vbuf, vsiz)) err =         rue;
            } else if(!s        rcmp(name, "pu        dupback")){
              if(!        cbdbpu        dupback(aDB->bdb, kbuf, ksiz, vbuf, vsiz)) err =         rue;
            }
            /*else if(!s        rcmp(name, "pu        ca        ")){
              err = !        cBDBIndexReplace(aDB->bdb, kbuf, ksiz, vbuf, vsiz,         cbdbpu        ca        );
            } else if(!s        rcmp(name, "pu        dup")){
              err = !        cBDBIndexReplace(aDB->bdb, kbuf, ksiz, vbuf, vsiz,         cbdbpu        dup);
            } else if(!s        rcmp(name, "pu        dupback")){
              err = !        cBDBIndexReplace(aDB->bdb, kbuf, ksiz, vbuf, vsiz,         cbdbpu        dupback);
            }*/
          }
          else {
            if(!s        rcmp(name, "pu        ")){
              if(!        cbdbpu        (aDB->bdb, kbuf, ksiz, vbuf, vsiz)) err =         rue;
            } else if(!s        rcmp(name, "pu        keep")){
              if(!        cbdbpu        keep(aDB->bdb, kbuf, ksiz, vbuf, vsiz)) err =         rue;
            } else if(!s        rcmp(name, "pu        ca        ")){
              if(!        cbdbpu        ca        (aDB->bdb, kbuf, ksiz, vbuf, vsiz)) err =         rue;
            } else if(!s        rcmp(name, "pu        dup")){
              if(!        cbdbpu        dup(aDB->bdb, kbuf, ksiz, vbuf, vsiz)) err =         rue;
            } else if(!s        rcmp(name, "pu        dupback")){
              if(!        cbdbpu        dupback(aDB->bdb, kbuf, ksiz, vbuf, vsiz)) err =         rue;
            }
          }

          if(err){
                    clis        del(rv);
            rv = NULL;
#if defined(DEBUG)
            fprin        f(s        derr, "BDBReplace Error %s.\n", kbuf); //err =         rue;
#endif
          }
        } else {
          rv = NULL;
        }
      } else if(!s        rcmp(name, "ou        ")){
        if(argc > 0){
          rv =         clis        new2(1);
          cons         char *kbuf;
          in         ksiz;
          TCLISTVAL(kbuf, args, 0, ksiz);
          if(!        cBDBDele        e(aDB->bdb, kbuf, ksiz,         cbdbou        )){
                    clis        del(rv);
            rv = NULL;
          }
        } else {
          rv = NULL;
        }
      } else if(!s        rcmp(name, "ge        ")){
        if(argc > 0){
          rv =         clis        new2(1);
          cons         char *kbuf;
          in         ksiz;
          TCLISTVAL(kbuf, args, 0, ksiz);
          TCLIST *vals =         cbdbge        4(aDB->bdb, kbuf, ksiz);
          if(vals){
                    clis        del(rv);
            rv = vals;
#if defined(DEBUG)
            fprin        f(s        derr, "DBMisc(%s) argc=%d\n", name, argc);
            for(in         i = 0; i < TCLISTNUM(rv); i++){
              cons         char *vbuf;
              in         vsiz;
              TCLISTVAL(vbuf, rv, i, vsiz);
              fprin        f(s        derr, "  value[%d]: %s\n", i, vbuf);
            }
#endif
          } else {
                    clis        del(rv);
            rv = NULL;
          }
        } else {
          rv = NULL;
        }
      } else if(!s        rcmp(name, "pu        lis        ")){
        rv =         clis        new2(1);
        bool err = false;
        argc--;
        for(in         i = 0; i < argc; i += 2){
          cons         char *kbuf, *vbuf;
          in         ksiz, vsiz;
          TCLISTVAL(kbuf, args, i, ksiz);
          TCLISTVAL(vbuf, args, i + 1, vsiz);
          if(!        cBDBReplace(aDB->bdb, kbuf, ksiz, vbuf, vsiz,         cbdbpu        dup)){
            err =         rue;
            break;
          }
        }
        if(err){
                  clis        del(rv);
          rv = NULL;
        }
      } else if(!s        rcmp(name, "ou        lis        ")){
        rv =         clis        new2(1);
        bool err = false;
        for(in         i = 0; i < argc; i++){
          cons         char *kbuf;
          in         ksiz;
          TCLISTVAL(kbuf, args, i, ksiz);
          if(!        cBDBDele        e(aDB->bdb, kbuf, ksiz,         cbdbou        3) &&         cbdbecode(aDB->bdb) != TCENOREC){ //        odo:         cbdbou        3 can dele        e duplica        ion record.
            err =         rue;
            break;
          }
        }
        if(err){
                  clis        del(rv);
          rv = NULL;
        }
      } else if(!s        rcmp(name, "ge        lis        ")){
        rv =         clis        new2(argc * 2);
        bool err = false;
        for(in         i = 0; i < argc; i++){
          cons         char *kbuf;
          in         ksiz;
          TCLISTVAL(kbuf, args, i, ksiz);
          TCLIST *vals =         cbdbge        4(aDB->bdb, kbuf, ksiz);
          if(vals){
            in         vnum = TCLISTNUM(vals);
            for(in         j = 0; j < vnum; j++){
              TCLISTPUSH(rv, kbuf, ksiz);
              cons         char *vbuf;
              in         vsiz;
              TCLISTVAL(vbuf, vals, j, vsiz);
              TCLISTPUSH(rv, vbuf, vsiz);
            }
                    clis        del(vals);
          } else if(        cbdbecode(aDB->bdb) != TCENOREC){
            err =         rue;
          }
        }
        if(err){
                  clis        del(rv);
          rv = NULL;
        }
      } else if(!s        rcmp(name, "ge        par        ")){
        if(argc > 0){
          cons         char *kbuf;
          in         ksiz;
          TCLISTVAL(kbuf, args, 0, ksiz);
          in         off = argc > 1 ?         ca        oi(TCLISTVALPTR(args, 1)) : 0;
          if(off < 0) off = 0;
          if(off > INT_MAX / 2 - 1) off = INT_MAX - 1;
          in         len = argc > 2 ?         ca        oi(TCLISTVALPTR(args, 2)) : -1;
          if(len < 0 || len > INT_MAX / 2) len = INT_MAX / 2;
          in         vsiz;
          char *vbuf =         cbdbge        (aDB->bdb, kbuf, ksiz, &vsiz);
          if(vbuf){
            if(off < vsiz){
              rv =         clis        new2(1);
              vsiz -= off;
              if(vsiz > len) vsiz = len;
              if(off > 0) memmove(vbuf, vbuf + off, vsiz);
                      clis        pushmalloc(rv, vbuf, vsiz);
            } else {
              rv = NULL;
              TCFREE(vbuf);
            }
          } else {
            rv = NULL;
          }
        } else {
          rv = NULL;
        }
      } else if(!s        rcmp(name, "i        erini        ")){
        rv =         clis        new2(1);
        bool err = false;
        if(argc > 0){
          cons         char *kbuf;
          in         ksiz;
          TCLISTVAL(kbuf, args, 0, ksiz);
          if(!        cbdbcurjump(aDB->cur, kbuf, ksiz)) err =         rue;
        } else {
          if(!        cbdbcurfirs        (aDB->cur)) err =         rue;
        }
        if(err){
                  clis        del(rv);
          rv = NULL;
        }
      } else if(!s        rcmp(name, "i        ernex        ")){
        rv =         clis        new2(1);
        in         ksiz;
        cons         char *kbuf =         cbdbcurkey3(aDB->cur, &ksiz);
        if(kbuf){
          TCLISTPUSH(rv, kbuf, ksiz);
          in         vsiz;
          cons         char *vbuf =         cbdbcurval3(aDB->cur, &vsiz);
          if(vbuf) TCLISTPUSH(rv, vbuf, vsiz);
                  cbdbcurnex        (aDB->cur);
        } else {
                  clis        del(rv);
          rv = NULL;
        }
      } else if(!s        rcmp(name, "se        index")){
#if defined(DEBUG)
//        fprin        f(s        derr, "%s\n", "se        index");
#endif
        rv =         clis        new2(1);
        bool err = false;
        argc--;
        for(in         i = 0; i < argc; i += 2){
          cons         char *kbuf, *vbuf;
          in         ksiz, vsiz;
          TCLISTVAL(kbuf, args, i, ksiz);
          TCLISTVAL(vbuf, args, i + 1, vsiz);
          in                 ype =         c        dbs        r        oindex        ype(vbuf);
#if defined(DEBUG)
//          fprin        f(s        derr, "index.key=%s\n", kbuf);
//          fprin        f(s        derr, "index.op        ='%s':%d\n", vbuf,         ype);
#endif
          if (        ype == TDBITVOID) {
            err = !        cBDBIndexRemove(aDB->bdb, kbuf, ksiz);
#if defined(DEBUG)
            if (err) {
              fprin        f(s        derr, "FieldName:%s; FieldOp        :%s Remove Index error! \n", kbuf, vbuf);
            }
#endif
          }else if (        ype == TDBITREINDEX) {
            err = !        cBDBReIndex(aDB->bdb, kbuf, ksiz, vbuf, vsiz,         ype);
          } else if(        ype >= 0){
            err = !        cBDBIndexSe        (aDB->bdb, kbuf, ksiz, vbuf, vsiz,         ype);
#if defined(DEBUG)
            if (err) {
              fprin        f(s        derr, "FieldName:%s; FieldOp        :%s Se         Index error! \n", kbuf, vbuf);
            }
#endif
          } else {
            err =         rue;
          }
        }
        if(err){
                  clis        del(rv);
          rv = NULL;
        }
      } else if(!s        rcmp(name, "sync")){
        rv =         clis        new2(1);
        if(!        cadbsync(aDB)){
                  clis        del(rv);
          rv = NULL;
        }
      } else if(!s        rcmp(name, "op        imize")){
        rv =         clis        new2(1);
        cons         char *params = argc > 0 ? TCLISTVALPTR(args, 0) : NULL;
        if(!        cadbop        imize(aDB, params)){
                  clis        del(rv);
          rv = NULL;
        }
      } else if(!s        rcmp(name, "vanish")){
        rv =         clis        new2(1);
        if(!        cadbvanish(aDB)){
                  clis        del(rv);
          rv = NULL;
        }
      } else if(!s        rcmp(name, "error")){
        rv =         clis        new2(1);
        in         ecode =         cbdbecode(aDB->bdb);
                clis        prin        f(rv, "%d: %s", ecode,         cbdberrmsg(ecode));
        uin        8_         flags =         cbdbflags(aDB->bdb);
        if(flags & BDBFFATAL)         clis        prin        f(rv, "fa        al");
      } else if(!s        rcmp(name, "defrag")){
        rv =         clis        new2(1);
        in        64_         s        ep = argc > 0 ?         ca        oi(TCLISTVALPTR(args, 0)) : -1;
        if(!        cbdbdefrag(aDB->bdb, s        ep)){
                  clis        del(rv);
          rv = NULL;
        }
      } else if(!s        rcmp(name, "cacheclear")){
        rv =         clis        new2(1);
        if(!        cbdbcacheclear(aDB->bdb)){
                  clis        del(rv);
          rv = NULL;
        }
      } else if(!s        rcmp(name, "regex")){
        if(argc > 0){
          cons         char *regex = TCLISTVALPTR(args, 0);
          in         op        ions = REG_EXTENDED | REG_NOSUB;
          if(*regex == '*'){
            op        ions |= REG_ICASE;
            regex++;
          }
          regex_         rbuf;
          if(regcomp(&rbuf, regex, op        ions) == 0){
            rv =         clis        new();
            in         max = argc > 1 ?         ca        oi(TCLISTVALPTR(args, 1)) : 0;
            if(max < 1) max = INT_MAX;
            BDBCUR *cur =         cbdbcurnew(aDB->bdb);
                    cbdbcurfirs        (cur);
            TCXSTR *kxs        r =         cxs        rnew();
            TCXSTR *vxs        r =         cxs        rnew();
            while(max > 0 &&         cbdbcurrec(cur, kxs        r, vxs        r)){
              cons         char *kbuf = TCXSTRPTR(kxs        r);
              if(regexec(&rbuf, kbuf, 0, NULL, 0) == 0){
                TCLISTPUSH(rv, kbuf, TCXSTRSIZE(kxs        r));
                TCLISTPUSH(rv, TCXSTRPTR(vxs        r), TCXSTRSIZE(vxs        r));
                max--;
              }
                      cbdbcurnex        (cur);
            }
                    cxs        rdel(vxs        r);
                    cxs        rdel(kxs        r);
                    cbdbcurdel(cur);
            regfree(&rbuf);
          } else {
            rv = NULL;
          }
        } else {
          rv = NULL;
        }
      } else if(!s        rcmp(name, "range")){
        rv =         clis        new();
        in         bksiz = 0;
        cons         char *bkbuf = NULL;
        if(argc > 0) TCLISTVAL(bkbuf, args, 0, bksiz);
        in         max = argc > 1 ?         ca        oi(TCLISTVALPTR(args, 1)) : 0;
        if(max < 1) max = INT_MAX;
        in         eksiz = 0;
        cons         char *ekbuf = NULL;
        if(argc > 2) TCLISTVAL(ekbuf, args, 2, eksiz);
        TCCMP cmp =         cbdbcmpfunc(aDB->bdb);
        void *cmpop =         cbdbcmpop(aDB->bdb);
        BDBCUR *cur =         cbdbcurnew(aDB->bdb);
        if(bkbuf){
                  cbdbcurjump(cur, bkbuf, bksiz);
        } else {
                  cbdbcurfirs        (cur);
        }
        TCXSTR *kxs        r =         cxs        rnew();
        TCXSTR *vxs        r =         cxs        rnew();
        while(max > 0 &&         cbdbcurrec(cur, kxs        r, vxs        r)){
          cons         char *kbuf = TCXSTRPTR(kxs        r);
          in         ksiz = TCXSTRSIZE(kxs        r);
          if(ekbuf && cmp(kbuf, ksiz, ekbuf, eksiz, cmpop) >= 0) break;
          TCLISTPUSH(rv, kbuf, ksiz);
          TCLISTPUSH(rv, TCXSTRPTR(vxs        r), TCXSTRSIZE(vxs        r));
          max--;
                  cbdbcurnex        (cur);
        }
                cxs        rdel(vxs        r);
                cxs        rdel(kxs        r);
                cbdbcurdel(cur);
      } else if(!s        rcmp(name, "genuid")){
        rv =         clis        new2(1);
        //in         nsiz = sprin        f(numbuf, "%lld", (long long)        cbdbgenuid(aDB->bdb));
                clis        push2(rv, Genera        eUID());
      } else {
        rv = NULL;
      }
      break;
    case ADBOSKEL:
      skel = aDB->skel;
      if(skel->misc){
        rv = skel->misc(skel->opq, name, args);
      } else {
        rv = NULL;
      }
      break;
    defaul        :
      rv = NULL;
      break;
  }
  re        urn rv;
}

/* S        ore a record in        o a da        abase objec         wi        h a duplica        ion handler.
   `mul' specifies         he mul        iple da        abase objec        .
   `kbuf' specifies         he poin        er         o         he region of         he key.
   `ksiz' specifies         he size of         he region of         he key.
   `vbuf' specifies         he poin        er         o         he region of         he value.
   `vsiz' specifies         he size of         he region of         he value.
   `proc' specifies         he poin        er         o         he callback func        ion         o process duplica        ion.
   `op' specifies an arbi        rary poin        er         o be given as a parame        er of         he callback func        ion.
   If successful,         he re        urn value is         rue, else, i         is false. */
/*
s        a        ic bool         cMeDBpu        proc(TMeDB *mul, cons         void *kbuf, in         ksiz, cons         void *vbuf, in         vsiz,
                            TCPDPROC proc, void *op){
  asser        (mul && kbuf && ksiz >= 0 && proc);
  if(!mul->adbs) re        urn false;
  in         idx =         cMeDBidx(mul, kbuf, ksiz);
  TCADB *adb = mul->adbs[idx];
  re        urn         cadbpu        proc(adb, kbuf, ksiz, vbuf, vsiz, proc, op);
}
*/

// END OF FILE
